package com.bosicloud.cmb.ibp.aws.adapter.component;


import com.bosicloud.cmb.ibp.QueueNames;
import com.bosicloud.cmb.ibp.aws.adapter.commom.dto.*;
import com.bosicloud.cmb.ibp.aws.adapter.commom.vo.CreateApiKeyVO;
import com.bosicloud.cmb.ibp.aws.adapter.config.RedisLock;
import com.bosicloud.cmb.ibp.aws.adapter.service.ApiGatewayService;
import com.bosicloud.cmb.ibp.commom.dto.exchange.ExchangeMessage;
import com.bosicloud.cmb.ibp.commom.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.aws.messaging.core.QueueMessagingTemplate;
import org.springframework.stereotype.Component;

import static com.bosicloud.cmb.ibp.aws.adapter.service.impl.ApiGatewayServiceImpl.getEnvFor;
import static com.bosicloud.cmb.ibp.commom.dto.exchange.ExchangeAction.*;

/**
 * @author Jack Peng
 */
@Component
@Slf4j
public class MessageExecutor {

    @Autowired
    RedisLock lock;

    @Autowired
    private ApiGatewayService apiGatewayService;

    @Autowired
    private QueueNames queueNames;

    @Autowired
    private QueueMessagingTemplate messagingTemplate;


    public void receiveLogic(ExchangeMessage payload) {

        switch (payload.getAction()) {
            case CREATE_KEY:
                createApiKey(payload);
                break;
            case CREATE_API:
                createApi(payload);
                break;
            case DEPLOY_KEY:
                deployApi(payload);
                break;
            case SUBSCRIBE_KEY:
                subscribeApi(payload);
                break;
            case UN_SUBSCRIBE_KEY:
                unSubscribeApi(payload);
                break;
            case DELETE_API_KEY:
                deleteApi(payload);
                break;
            default:
                break;
        }
    }

    private void createApiKey(ExchangeMessage payload) {

        String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-AWS-Adapter CreateApiKey Receive Message:{}", toJson);

        CreateApiKeyVO createApiKeyVO = JsonUtil.parse(toJson, CreateApiKeyVO.class);

        String lockKey = createApiKeyVO.getUserId() + getEnvFor(createApiKeyVO.getIsTest()) + CREATE_KEY;
        if (lock.lock(lockKey)) {
            try {
                // 发送创建ApiKey消息
                this.sendMessage(queueNames.getResponseAccount(), CREATE_KEY,
                        apiGatewayService.createApiKey(createApiKeyVO.getUserId(), createApiKeyVO.getIsTest()));

            } catch (Exception e) {
                log.error("### create api key error,message:{}", e.getMessage(), e);

            } finally {
                lock.unlock(lockKey);
            }
        }

    }

    private void createApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-AWS-Adapter CreateApi receive message:{}", toJson);

        final CreateApiParamDTO createApiParamDTO = JsonUtil.parse(toJson, CreateApiParamDTO.class);
        final String apiId = createApiParamDTO.getApiId();

        final String lockKey = apiId + CREATE_API;
        if (lock.lock(lockKey)) {
            try {

                CreateApiResultDTO resultDTO = apiGatewayService.createApiGateway(createApiParamDTO.getJsonUrl(), false);
                resultDTO.setApiId(apiId);
                // 发送创建ApiKey消息
                this.sendMessage(queueNames.getResponseApiManager(), CREATE_API, resultDTO);

            } catch (Exception e) {
                log.error("### Create API fail,message:{}", e.getMessage(), e);

                this.sendMessage(queueNames.getResponseApiManager(), CREATE_API, CreateApiResultDTO
                        .builder()
                        .keyId("")
                        .apiId(apiId)
                        .errorMessage(e.getMessage())
                        .isSuccess(false)
                        .build());

            } finally {
                lock.unlock(lockKey);
            }
        }
    }

    private void deployApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-AWS-Adapter Deploy Api receive message:{}", toJson);

        final DeployApiParamDTO paramDTO = JsonUtil.parse(toJson, DeployApiParamDTO.class);
        final String apiId = paramDTO.getApiId();
        final String awsApiId = paramDTO.getAwsApiId();
        final String stageName = paramDTO.getStageName();
        final String keyId = paramDTO.getKeyId();

        final String lockKey = apiId + awsApiId + keyId + stageName + DEPLOY_KEY;
        if (lock.lock(lockKey)) {
            try {

                DeployApiResultDTO resultDTO = apiGatewayService.deployApi(paramDTO);
                resultDTO.setApiId(apiId);
                resultDTO.setIsSuccess(true);
                resultDTO.setStage(stageName);
                // 发送创建ApiKey消息
                this.sendMessage(queueNames.getResponseApiManager(), DEPLOY_KEY, resultDTO);

            } catch (Exception e) {
                log.error("### Deploy API fail,message:{}", e.getMessage(), e);

                this.sendMessage(queueNames.getResponseApiManager(), DEPLOY_KEY, DeployApiResultDTO
                        .builder()
                        .apiId(apiId)
                        .awsApiId(paramDTO.getAwsApiId())
                        .errorMessage(e.getMessage())
                        .isSuccess(false)
                        .stage(stageName)
                        .endpoint(paramDTO.getEndpointUrl())
                        .build());

            } finally {
                lock.unlock(lockKey);
            }
        }
    }


    private void subscribeApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-AWS-Adapter SubscribeApi   receive message:{}", toJson);

        final SubscribeApiParamDTO paramDTO = JsonUtil.parse(toJson, SubscribeApiParamDTO.class);
        final String apiId = paramDTO.getApiId();
        final String userId = paramDTO.getUserId();
        final String usagePlanId = paramDTO.getUsagePlanId();
        final String keyId = paramDTO.getKeyId();

        SubscribeApiResultDTO.SubscribeApiResultDTOBuilder builder = SubscribeApiResultDTO
                .builder()
                .userId(userId)
                .apiId(apiId)
                .isSuccess(true);

        final String lockKey = apiId + userId + keyId + usagePlanId + SUBSCRIBE_KEY;
        if (lock.lock(lockKey)) {

            try {

                builder.subscribeId(apiGatewayService.subscribeApi(keyId, usagePlanId));
                //发送订阅消息
                this.sendMessage(queueNames.getResponseApiManager(), SUBSCRIBE_KEY, builder.build());

            } catch (Exception e) {
                log.error("### Subscribe Api fail,message:{}", e.getMessage(), e);

                builder.errorMessage(e.getMessage()).isSuccess(false);
                //发送订阅消息
                this.sendMessage(queueNames.getResponseApiManager(), SUBSCRIBE_KEY, builder.build());

            } finally {
                lock.unlock(lockKey);
            }
        }
    }

    private void unSubscribeApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-AWS-Adapter unSubscribeApi   receive message:{}", toJson);

        final SubscribeApiParamDTO paramDTO = JsonUtil.parse(toJson, SubscribeApiParamDTO.class);
        final String apiId = paramDTO.getApiId();
        final String userId = paramDTO.getUserId();
        final String usagePlanId = paramDTO.getUsagePlanId();
        final String keyId = paramDTO.getKeyId();

        SubscribeApiResultDTO.SubscribeApiResultDTOBuilder builder = SubscribeApiResultDTO
                .builder()
                .userId(userId)
                .apiId(apiId)
                .isSuccess(true);

        final String lockKey = apiId + userId + keyId + usagePlanId + UN_SUBSCRIBE_KEY;
        if (lock.lock(lockKey)) {

            try {

                builder.subscribeId(apiGatewayService.unsubscribeApi(keyId, usagePlanId));
                //发送取消订阅消息
                this.sendMessage(queueNames.getResponseApiManager(), UN_SUBSCRIBE_KEY, builder.build());

            } catch (Exception e) {
                log.error("### unSubscribe Api fail,message:{}", e.getMessage(), e);

                builder.errorMessage(e.getMessage()).isSuccess(false);
                //发送取消订阅消息
                this.sendMessage(queueNames.getResponseApiManager(), UN_SUBSCRIBE_KEY, builder.build());

            } finally {
                lock.unlock(lockKey);
            }
        }
    }


    private void deleteApi(ExchangeMessage payload) {

        final String toJson = JsonUtil.toJson(payload.getData());
        log.info("### IBP-AWS-Adapter Delete Api   receive message:{}", toJson);

        final DeleteApiParamDTO paramDTO = JsonUtil.parse(toJson, DeleteApiParamDTO.class);
        final String apiId = paramDTO.getApiId();
        final String userId = paramDTO.getUserId();

        DeleteApiResultDTO.DeleteApiResultDTOBuilder builder = DeleteApiResultDTO
                .builder()
                .userId(userId)
                .apiId(apiId)
                .isSuccess(true);
        final String lockKey = apiId + userId + DELETE_API_KEY;
        if (lock.lock(lockKey)) {
            try {

                apiGatewayService.deleteApiGateway(paramDTO.getAwsApiId());
                // 发送删除Api消息
                this.sendMessage(queueNames.getResponseApiManager(), DELETE_API_KEY, builder.build());

            } catch (Exception e) {
                log.error("### Delete API fail,message:{}", e.getMessage(), e);

                builder.errorMessage(e.getMessage()).isSuccess(false);
                // 发送删除Api消息
                this.sendMessage(queueNames.getResponseApiManager(), DELETE_API_KEY, builder.build());

            } finally {
                lock.unlock(lockKey);
            }
        }
    }


    private void sendMessage(String targetQueueName, String action, Object data) {

        log.info("### Send message to target queue,name is:{},DATA is:{}",
                targetQueueName, JsonUtil.toJson(data));
        messagingTemplate.convertAndSend(targetQueueName,
                ExchangeMessage.builder()
                        .Action(action)
                        .data(data)
                        .build());
        log.info("### Send message end.");
    }
}
